package com.glsc.ngateway.platform.service.itflow.flowstrategy.cmdb.partIn.taskPostHandler;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.glsc.ngateway.common.api.common.enums.Constant;
import com.glsc.ngateway.common.api.common.enums.RabbitExcQueConstant;
import com.glsc.ngateway.common.api.flowable.dto.FlowFormCPUInDetailDto;
import com.glsc.ngateway.common.api.flowable.dto.FlowFormDiskInDetailDto;
import com.glsc.ngateway.common.api.flowable.dto.FlowFormMemoryInDetailDto;
import com.glsc.ngateway.common.api.flowable.dto.FlowFormPartInDetailDto;
import com.glsc.ngateway.common.api.flowable.dto.task.doTaskParam.cmdb.CMDBPassParamDto;
import com.glsc.ngateway.common.api.flowable.dto.task.doTaskParam.cmdb.CMDBRejectParamDto;
import com.glsc.ngateway.common.api.flowable.dto.task.formData.cmdb.PartInTaskFormDto;
import com.glsc.ngateway.common.api.flowable.dto.task.formData.cmdb.domainDto.FlowFormPartInDto;
import com.glsc.ngateway.common.api.flowable.dto.task.message.SystemFlowMessageDto;
import com.glsc.ngateway.common.api.flowable.resp.ResponseSituationDto;
import com.glsc.ngateway.common.api.ldap.dto.LdapEhrEmpDto;
import com.glsc.ngateway.common.api.ldap.feign.IFeignLdapService;
import com.glsc.ngateway.common.api.ldap.resp.AppEhrResponse;
import com.glsc.ngateway.common.api.oaflow.feign.IFeignOaFlowService;
import com.glsc.ngateway.common.api.oaflow.resp.InterfaceResponse;
import com.glsc.ngateway.common.base.domain.mysql.cmdb.CmdbCpuStandard;
import com.glsc.ngateway.common.base.domain.mysql.cmdb.CmdbDiskStandard;
import com.glsc.ngateway.common.base.domain.mysql.cmdb.CmdbMemoryStandard;
import com.glsc.ngateway.common.base.domain.mysql.cmdb.CmdbPartStandard;
import com.glsc.ngateway.common.base.domain.mysql.gateway.platform.flow.FlowPushOaLog;
import com.glsc.ngateway.common.base.enums.itflow.ITFlowEnum;
import com.glsc.ngateway.common.base.enums.itflow.ITFlowTaskEnum;
import com.glsc.ngateway.common.base.repo.mysql.gateway.platform.flow.FlowPushOaLogRepo;
import com.glsc.ngateway.platform.service.FlowCommonService;
import com.glsc.ngateway.platform.service.SystemConfigService;
import com.glsc.ngateway.platform.service.cmdb.CmdbCpuStandardService;
import com.glsc.ngateway.platform.service.cmdb.CmdbDiskStandardService;
import com.glsc.ngateway.platform.service.cmdb.CmdbMemoryStandardService;
import com.glsc.ngateway.platform.service.cmdb.CmdbPartStandardService;
import com.glsc.ngateway.platform.service.itflow.flowstrategy.IItFlowMQHandler;
import com.glsc.ngateway.platform.service.itflow.flowstrategy.cmdb.partIn.PartInFlowStrategy;
import com.glsc.ngateway.platform.utils.MqUtil;
import org.apache.logging.log4j.util.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.validation.constraints.NotNull;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zhengyr
 * @date 2023/8/2-16:16
 */
@Component
public class PIStep3ConfirmTaskPostHandlerAudit implements IPartInTaskPostHandlerAudit, IItFlowMQHandler {

    Logger logger = LoggerFactory.getLogger(PIStep3ConfirmTaskPostHandlerAudit.class);
    @Autowired
    PartInFlowStrategy partInFlowStrategy;
    @Autowired
    PIStepHandlerHelper handlerHelper;
    @Autowired
    private FlowCommonService flowCommonService;
    @Resource
    private IFeignOaFlowService oaFlowService;
    @Resource
    private SystemConfigService systemConfigService;
    @Resource
    private FlowPushOaLogRepo flowPushOaLogRepo;
    @Resource
    private IFeignLdapService feignLdapService;
    @Resource
    private CmdbCpuStandardService cmdbCpuStandardService;
    @Resource
    private CmdbMemoryStandardService cmdbMemoryStandardService;
    @Resource
    private CmdbDiskStandardService cmdbDiskStandardService;
    @Resource
    private CmdbPartStandardService cmdbPartStandardService;


    @Override
    public void doHandle(String msg) {
        //更新配件库数据
//        SystemFlowMessageDto msgJsonObject = JSONObject.parseObject(msg, SystemFlowMessageDto.class);
//        handlerHelper.updatePartData(msgJsonObject.getProcessId(), msgJsonObject.getOperator());
//        //更新数据后抄送给领导
//        handlerHelper.endTaskAfterHandle(msgJsonObject.getProcessId(), msgJsonObject.getOperator());
    }

    @Override
    public String getTaskDefinitionKey() {
        return ITFlowTaskEnum.CMDB_PART_IN_FLOW_CREATOR_AUDIT_TASK.getTaskKey();
    }

    @Override
    public String getMqCodeKey() {
        return ITFlowTaskEnum.CMDB_PART_IN_FLOW_CREATOR_AUDIT_TASK.getMqCodeKey();
    }

    //重写方法权限升级为public，里氏代换原则--任何基类可以出现的地方，子类一定可以出现
    @Override
    public void passAfterHandle(@NotNull CMDBPassParamDto<FlowFormPartInDto, PartInTaskFormDto> passParam, @NotNull String operator) throws Exception {
        ResponseSituationDto processInfo = flowCommonService.getProcessInfo(passParam.getProcessId());

        handlerHelper.updatePartData(passParam.getProcessId(), operator);
        //更新数据后抄送给领导
        handlerHelper.endTaskAfterHandle(passParam.getProcessId(), passParam.getFlowableFormData().getFormMainData().getFlowCreateOperatorAccount());

        //通知oa发起【资产入库申请流程】
        FlowFormPartInDto formMainData = passParam.getFlowableFormData().getFormMainData();
        String wfid = systemConfigService.findByCode(Constant.OA_FLOW_ASSET_INVENTORY_WFID).getConfigValue();
        //OA-资产名称项：机房配件（资产报销）
        Integer device = Integer.valueOf(systemConfigService.findByCode("OA_FLOW_ASSET_INVENTORY_DEVICE_MACHINE_ROME").getConfigValue());
        AppEhrResponse<LdapEhrEmpDto> ldapResp = feignLdapService.getLdapEhrEmp(formMainData.getFlowCreateOperatorAccount(), null, false);
        if (Objects.isNull(ldapResp) || !ldapResp.isSuccess() || Objects.isNull(ldapResp.getData())) {
            logger.error("创建流程失败，未找到oa流程发起人，{}", formMainData.getFlowCreateOperatorAccount());
            return;
        }
        LdapEhrEmpDto appInfo = ldapResp.getData();
        List<JSONObject> detailList = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(passParam.getFlowableFormData().getCpuInDataList())) {
            Map<String, LdapEhrEmpDto> empMap = feignLdapService.getEmpsByAccounts(
                            passParam.getFlowableFormData().getCpuInDataList().stream()
                                    .map(FlowFormCPUInDetailDto::getUser)
                                    .collect(Collectors.toList()))
                    .getData()
                    .stream()
                    .collect(Collectors.toMap(LdapEhrEmpDto::getBadge, e -> e));
            detailList.addAll(passParam.getFlowableFormData().getCpuInDataList().stream()
                    .map(data -> {
                        data.setAsset(device);
                        CmdbCpuStandard cpuStandard = cmdbCpuStandardService.findByStandardCode(data.getCpuStandardCode());
                        //配件发起oa时，使用规格名称
                        data.setPartNum(Objects.nonNull(cpuStandard) ? cpuStandard.getName() : null);
                        JSONObject obj = (JSONObject) JSON.toJSON(data);
                        LdapEhrEmpDto userInfo = empMap.get(data.getUser());
                        obj.put("userDepart", Objects.nonNull(userInfo) ? userInfo.getOaDeptId() : Strings.EMPTY);
                        obj.put("userComp", Objects.nonNull(userInfo) ? userInfo.getOaCompId() : Strings.EMPTY);
                        //资产类型：0=电    办=1    配=2
                        obj.put("assetType", "2");
                        return obj;
                    })
                    .collect(Collectors.toList()));
        }
        if (CollectionUtil.isNotEmpty(passParam.getFlowableFormData().getMemoryInDataList())) {
            Map<String, LdapEhrEmpDto> empMap = feignLdapService.getEmpsByAccounts(
                            passParam.getFlowableFormData().getMemoryInDataList().stream()
                                    .map(FlowFormMemoryInDetailDto::getUser)
                                    .collect(Collectors.toList()))
                    .getData()
                    .stream()
                    .collect(Collectors.toMap(LdapEhrEmpDto::getBadge, e -> e));
            detailList.addAll(passParam.getFlowableFormData().getMemoryInDataList().stream()
                    .map(data -> {
                        data.setAsset(device);
                        CmdbMemoryStandard memoryStandard = cmdbMemoryStandardService.findByStandardCode(data.getMemoryStandardCode());
                        //配件发起oa时，使用规格名称
                        data.setPartNum(Objects.nonNull(memoryStandard) ? memoryStandard.getName() : null);
                        JSONObject obj = (JSONObject) JSON.toJSON(data);
                        LdapEhrEmpDto userInfo = empMap.get(data.getUser());
                        obj.put("userDepart", Objects.nonNull(userInfo) ? userInfo.getOaDeptId() : Strings.EMPTY);
                        obj.put("userComp", Objects.nonNull(userInfo) ? userInfo.getOaCompId() : Strings.EMPTY);
                        //资产类型：0=电    办=1    配=2
                        obj.put("assetType", "2");
                        return obj;
                    })
                    .collect(Collectors.toList()));
        }
        if (CollectionUtil.isNotEmpty(passParam.getFlowableFormData().getDiskInDataList())) {
            Map<String, LdapEhrEmpDto> empMap = feignLdapService.getEmpsByAccounts(
                            passParam.getFlowableFormData().getDiskInDataList().stream()
                                    .map(FlowFormDiskInDetailDto::getUser)
                                    .collect(Collectors.toList()))
                    .getData()
                    .stream()
                    .collect(Collectors.toMap(LdapEhrEmpDto::getBadge, e -> e));
            detailList.addAll(passParam.getFlowableFormData().getDiskInDataList().stream()
                    .map(data -> {
                        data.setAsset(device);
                        CmdbDiskStandard diskStandard = cmdbDiskStandardService.findByStandardCode(data.getDiskStandardCode());
                        //配件发起oa时，使用规格名称
                        data.setPartNum(Objects.nonNull(diskStandard) ? diskStandard.getName() : null);
                        JSONObject obj = (JSONObject) JSON.toJSON(data);
                        LdapEhrEmpDto userInfo = empMap.get(data.getUser());
                        obj.put("userDepart", Objects.nonNull(userInfo) ? userInfo.getOaDeptId() : Strings.EMPTY);
                        obj.put("userComp", Objects.nonNull(userInfo) ? userInfo.getOaCompId() : Strings.EMPTY);
                        //资产类型：0=电    办=1    配=2
                        obj.put("assetType", "2");
                        return obj;
                    })
                    .collect(Collectors.toList()));
        }
        if (CollectionUtil.isNotEmpty(passParam.getFlowableFormData().getPartInDataList())) {
            Map<String, LdapEhrEmpDto> empMap = feignLdapService.getEmpsByAccounts(
                            passParam.getFlowableFormData().getPartInDataList().stream()
                                    .map(FlowFormPartInDetailDto::getUser)
                                    .collect(Collectors.toList()))
                    .getData()
                    .stream()
                    .collect(Collectors.toMap(LdapEhrEmpDto::getBadge, e -> e));
            detailList.addAll(passParam.getFlowableFormData().getPartInDataList().stream()
                    .map(data -> {
                        data.setAsset(device);
                        CmdbPartStandard partStandard = cmdbPartStandardService.findByStandardCode(data.getPartStandardCode());
                        //配件发起oa时，使用规格名称
                        data.setPartNum(Objects.nonNull(partStandard) ? partStandard.getName() : null);
                        JSONObject obj = (JSONObject) JSON.toJSON(data);
                        LdapEhrEmpDto userInfo = empMap.get(data.getUser());
                        obj.put("userDepart", Objects.nonNull(userInfo) ? userInfo.getOaDeptId() : Strings.EMPTY);
                        obj.put("userComp", Objects.nonNull(userInfo) ? userInfo.getOaCompId() : Strings.EMPTY);
                        //资产类型：0=电    办=1    配=2
                        obj.put("assetType", "2");
                        return obj;
                    })
                    .collect(Collectors.toList()));
        }

        Map<String, Object> dataMap = new HashMap<>() {{
            put("title", String.format("01.资产入库申请流程-%s-%s", formMainData.getFlowCreateOperatorName(), formMainData.getProcessCreateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))));
            put("applicant", formMainData.getFlowCreateOperatorAccount());
            put("creater", formMainData.getFlowCreateOperatorAccount());
            //公司
            put("applicantComp", appInfo.getOaCompId().toString());
            //部门
            put("applicantDepart", appInfo.getOaDeptId().toString());
            //申请日期
            put("applyDate", LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
            put("detailList", detailList);
        }};
        InterfaceResponse<Map<String, String>> resp = JSONObject.parseObject(oaFlowService.createOaFlow(dataMap, wfid, "1", false), InterfaceResponse.class);
        flowPushOaLogRepo.save(FlowPushOaLog.builder()
                .processKey(ITFlowEnum.CMDB_PART_IN.getKey())
                .taskKey(ITFlowTaskEnum.CMDB_PART_IN_FLOW_SYNC_OA_TASK.getTaskKey())
                .processId(processInfo.getProcessId())
                .taskId(processInfo.getCurrentTaskId())
                .workflowId(wfid)
                .requestId(resp.getData().get("requestid"))
                .creator(formMainData.getCreateAccount())
                .pushResult(JSONObject.toJSONString(resp))
                .build());
        //如果当前节点走完，发送MQ，添加系统数据
        if (!this.getTaskDefinitionKey().equals(processInfo.getCurrentTaskDefinitionKey())) {
            SystemFlowMessageDto message = new SystemFlowMessageDto();
            message.setProcessId(passParam.getProcessId());
            message.setDefineKey(this.getMqCodeKey());
            message.setOperator(operator);
            MqUtil.sendMessage(RabbitExcQueConstant.AMPRODUCT_EXCHANGE_DEFAULT, RabbitExcQueConstant.AMPRODUCT_QUEUE_GATEWAY_FLOW_REMIND, message);
        }
    }

    /**
     * 驳回后置处理方法
     */
    @Override
    public void rejectAfterHandle(@NotNull CMDBRejectParamDto param, @NotNull String operator) {
        handlerHelper.afterHandle(param, operator);
    }

}
